﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Drivers;
using System.IO.Ports;
using Modbus.Data;
using Modbus.Device;
using Modbus.Utility;
using System.Runtime.InteropServices;
using USBInterface;
using System.Collections.ObjectModel;

namespace WevPanel
{
    public partial class FormAntiCog : Form
    {
        public SerialPort port = new SerialPort();
        public WaveGrapher grapher;
        public ObservableCollection<CurvePoint> anti_torque_curve = new ObservableCollection<CurvePoint>();
        private ModbusSerialMaster master;
        private byte slave_id = 1;
        public double SensorTorque = 0.0;
        public double MotorPos = 0.0;
        public bool ModbusReady { get; set; } = false;
        public FormAntiCog()
        {
            InitializeComponent();
            grapher = new WaveGrapher(ref Zed);
            btnAddPoint.Click += (sender, e) => { ShowCurve(); };
            btnDeletePoint.Click += (sender, e) => { ShowCurve(); };
            InitGraph();
        }

        public void ShowCurve()
        {
            double[][] points = FormUserCurves.ToPoints(anti_torque_curve);
            grapher.ShowCurve(
                Zed.GraphPane.Title.Text, 
                points[0], 
                points[1],
                Zed.GraphPane.XAxis.Title.Text,
                Zed.GraphPane.YAxis.Title.Text
                );
            RefreshDataViewer();
        }

        private void RefreshDataViewer()
        {
            CurveDataViewer.DataSource = null;
            CurveDataViewer.DataSource = anti_torque_curve;
            CurveDataViewer.Refresh();
        }

        private void InitGraph()
        {
            var pane = Zed.GraphPane;
            pane.Title.Text = "AntiCog Torque";
            pane.XAxis.Title.Text = "motor position";
            pane.YAxis.Title.Text = "torque";
            pane.XAxis.MajorGrid.IsVisible = true;
            pane.YAxis.MajorGrid.IsVisible = true;
        }

        public void RefreshPorts()
        {
            comboSerials.Items.Clear();
            foreach (var item in Transport.ListPorts())
            {
                comboSerials.Items.Add(item);
            }
            if (comboSerials.Items.Count > 0)
            {
                comboSerials.SelectedIndex = 0;
            }
        }

        private void FormAntiCog_Load(object sender, EventArgs e)
        {
            RefreshPorts();
        }

        private void FormAntiCog_FormClosing(object sender, FormClosingEventArgs e)
        {
            Hide();
            e.Cancel = true;
        }

        private void btnConnect_Click(object sender, EventArgs e)
        {
            try
            {
                if (port.IsOpen) port.Close();
                ModbusReady = false;
                port.PortName = comboSerials.Text;
                port.BaudRate = 19200;
                port.DataBits = 8;
                port.Parity = Parity.None;
                port.StopBits = StopBits.One;
                port.ReadTimeout = 100;
                port.Open();
                master = ModbusSerialMaster.CreateRtu(port);
                ModbusReady = true;
                ModbusTorque();
                tmBkg.Start();
            }
            catch (Exception ex)
            {
                ModbusReady = false;
                Console.WriteLine(ex.Message);
            }
        }

        public int ModbusTorque()
        {
            if (!ModbusReady) {
                throw new Exception("Modbus Not Ready.");
            }
            ushort startAddress = 0;
            ushort numRegisters = 2;
            ushort[] registers = master.ReadHoldingRegisters(slave_id, startAddress, numRegisters);
            uint register32 = (uint)(registers[0] << 16) | registers[1];
            byte[] torque_bytes = BitConverter.GetBytes(register32);
            int torque = BitConverter.ToInt32(torque_bytes, 0);
            // Console.WriteLine($"Torque {torque}");
            return torque;
        }

        private void tmBkg_Tick(object sender, EventArgs e)
        {
            checkModbusReady.Checked = ModbusReady;
            try
            {
                var torque = ModbusTorque();
                SensorTorque = torque / 1000.0;
                MotorPos = FormMain.SerialDriver_.Slave.WevDriver.Encoder.ActualPos;
                lbPos.Text = $"{MotorPos} Deg";
                lbTorque.Text = $"{SensorTorque} Nm";
                torqueBar.Value = (int)(Math.Abs(SensorTorque) * 100.0 / 3.0);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                checkModbusReady.Checked = false;
                ModbusReady = false;
                tmBkg.Stop();
            }
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            port.Close();
        }

        private void btnAddPoint_Click(object sender, EventArgs e)
        {
            var p = new CurvePoint((float)MotorPos, (float)SensorTorque);
            anti_torque_curve.Add(p);
        }

        private void btnDeletePoint_Click(object sender, EventArgs e)
        {
            if(anti_torque_curve.Count > 0)
            {
                anti_torque_curve.Remove(anti_torque_curve[CurveDataViewer.CurrentRow.Index]);
            }
        }

    }
}
